/* Copyright (C) 2009 Christofer Jonsson
 *
 * This file is part of FNM.
 *
 * FNM is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * FNM is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
 * License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with FNM.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "fnm_cmd.h"
#include "fnm_str.h"
#include "fnm_util.h"
#include "fnm_version.h"
#include "fnm_error.h"
#include "fnm_debug.h"
#include "fnm_global.h"
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

static const char error_msg_no_files[]  = "No files";
static const char error_msg_arg_count[] = "Wrong number of arguments";

static fnm_bool_t input_valid_lower_case(int nargs);
static fnm_bool_t input_valid_upper_case(int nargs);
static fnm_bool_t input_valid_replace(int nargs);

fnm_status_t fnm_cmd_lower_case(int nargs, 
				const char **args, 
				fnm_cmd_func_rename_t rn)
{
   const char *old_name = NULL;
   fnm_str_t new_name = { NULL, 0 };
   fnm_status_t res = FNM_FAILURE;
   size_t pos = 0;
   int i = 0;

   if (input_valid_lower_case(nargs) == FNM_FALSE)
      return FNM_FAILURE;

   for (i = 0; i < nargs; ++i)
   {
      old_name = args[i];
      fnm_str_init(&new_name, old_name);
      res = fnm_util_filename(new_name.str, new_name.len, &pos);

      if (res == FNM_FAILURE)
      {
	 FNM_ERROR("Filename is invalid: %s", old_name);
	 goto failed;
      }

      fnm_str_lower_case(&new_name, pos);
      FNM_DEBUG("Renaming: %s -> %s", old_name, new_name.str);

      if (rn(old_name, new_name.str) != 0)
      {
	 FNM_ERROR("Unable to rename file: %s: %s", old_name, strerror(errno));
	 goto failed;
      }

      fnm_str_destroy(&new_name);
   }

   return FNM_SUCCESS;

  failed:
   
   fnm_str_destroy(&new_name);
   return FNM_FAILURE;
}

fnm_status_t fnm_cmd_upper_case(int nargs, 
				const char **args, 
				fnm_cmd_func_rename_t rn)
{
   const char *old_name = NULL;
   fnm_str_t new_name = { NULL, 0 };
   fnm_status_t res = FNM_FAILURE;
   size_t pos = 0;
   int i = 0;

   if (input_valid_upper_case(nargs) == FNM_FALSE)
      return FNM_FAILURE;
   
   for (i = 0; i < nargs; ++i)
   {
      old_name = args[i];
      fnm_str_init(&new_name, old_name);
      res = fnm_util_filename(new_name.str, new_name.len, &pos);

      if (res == FNM_FAILURE)
      {
	 FNM_ERROR("Filename is invalid: %s", old_name);
	 goto failed;
      }

      fnm_str_upper_case(&new_name, pos);
      FNM_DEBUG("Renaming: %s -> %s", old_name, new_name.str);

      if (rn(old_name, new_name.str) != 0)
      {
	 FNM_ERROR("Unable to rename file: %s: %s", old_name, strerror(errno));
	 goto failed;
      }

      fnm_str_destroy(&new_name);
   }

   return FNM_SUCCESS;

  failed:
   
   fnm_str_destroy(&new_name);
   return FNM_FAILURE;
}

fnm_status_t fnm_cmd_replace(int nargs, 
			     const char **args, 
			     fnm_cmd_func_rename_t rn)
{
   const char *old_name = NULL;
   fnm_str_t new_name = { NULL, 0 };
   fnm_str_t old_sub = { NULL, 0 };
   fnm_str_t new_sub = { NULL, 0 };
   fnm_status_t res = FNM_FAILURE;
   size_t pos = 0;
   int i = 0;

   if (input_valid_replace(nargs) == FNM_FALSE)
      return FNM_FAILURE;

   fnm_str_init(&old_sub, args[0]);
   fnm_str_init(&new_sub, args[1]);

   for (i = 2; i < nargs; ++i)
   {
      old_name = args[i];
      fnm_str_init(&new_name, old_name);
      res = fnm_util_filename(new_name.str, new_name.len, &pos);

      if (res == FNM_FAILURE)
      {
	 FNM_ERROR("Filename is invalid: %s", old_name);
	 goto failed;
      }

      fnm_str_replace(&new_name, &old_sub, &new_sub, pos);
      FNM_DEBUG("Renaming: %s -> %s", old_name, new_name.str);

      if (rn(old_name, new_name.str) != 0)
      {
	 FNM_ERROR("Unable to rename file: %s: %s", old_name, strerror(errno));
	 goto failed;
      }

      fnm_str_destroy(&new_name);
   }

   fnm_str_destroy(&old_sub);
   fnm_str_destroy(&new_sub);
   fnm_str_destroy(&new_name);
   return FNM_SUCCESS;

  failed:

   fnm_str_destroy(&old_sub);
   fnm_str_destroy(&new_sub);
   fnm_str_destroy(&new_name);
   return FNM_FAILURE;
}

void fnm_cmd_version()
{
   printf("%s\n", FNM_VERSION_STR);
}

static fnm_bool_t input_valid_lower_case(int nargs)
{
   if (nargs == 0)
   {
      FNM_ERROR(error_msg_no_files);
      return FNM_FALSE;
   }

   return FNM_TRUE;
}

static fnm_bool_t input_valid_upper_case(int nargs)
{
   if (nargs == 0)
   {
      FNM_ERROR(error_msg_no_files);
      return FNM_FALSE;
   }

   return FNM_TRUE;
}

static fnm_bool_t input_valid_replace(int nargs)
{
   const int min_args = 2;

   if (nargs < min_args)
   {
      FNM_ERROR(error_msg_arg_count);
      return FNM_FALSE;
   }

   if (nargs - min_args == 0)
   {
      FNM_ERROR(error_msg_no_files);
      return FNM_FALSE;
   }

   return FNM_TRUE;
}
